package net.cloudcodex.client.storyboard.command.view;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.cloudcodex.client.widgets.spinner.SpinnerListener;
import net.cloudcodex.client.widgets.spinner.ValueSpinner;
import net.cloudcodex.shared.MessageAction;

import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.LayoutPanel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.TabLayoutPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.inject.Inject;

public class CommandViewImpl extends TabLayoutPanel implements CommandView {

	public class CommandTabImpl extends LayoutPanel implements CommandTab {
		private final TextArea messageArea = new TextArea();
		private final Button button = new Button();

		public CommandTabImpl(Unit unit, String buttonText) {
			this.add(this.messageArea);
			this.setWidgetLeftRight(this.messageArea, 0, Unit.PX, 0, Unit.PX);
			this.setWidgetTopHeight(this.messageArea, 0, Unit.PX, 80, Unit.PX);
			this.button.setText(buttonText);
			this.add(this.button);
			this.setWidgetRightWidth(this.button, 0, Unit.PX, 100, Unit.PX);
			this.setWidgetBottomHeight(this.button, 0, Unit.PX, 30, Unit.PX);
		}

		public TextArea getTextArea() {
			return this.messageArea;
		}

		public String getMessage() {
			return this.messageArea.getValue();
		}

		@Override
		public void emptyMessage() {
			this.messageArea.setValue(null);
		}

		public Button getButton() {
			return this.button;
		}
	}

	public class DiceLine extends DockLayoutPanel {
		private final ValueSpinner dice = new ValueSpinner(1, 1, 10);
		private final ValueSpinner sides = new ValueSpinner(6, 2, 100);

		private final SpinnerListener diceSpinnerListener;

		public DiceLine() {
			super(Unit.PX);

			final Label roll = new Label(message.getLabelRoll());
			final Label diceOf = new Label(message.getLabelDiceOf(1));
			final Label side = new Label(message.getLabelSide());

			final String diceLineLabelStyle = constant.getDiceLineLabelStyle();
			roll.addStyleName(diceLineLabelStyle);
			diceOf.addStyleName(diceLineLabelStyle);
			side.addStyleName(diceLineLabelStyle);

			this.diceSpinnerListener = new SpinnerListener() {
				public void onSpinning(long value) {
					diceOf.setText(message.getLabelDiceOf((int) value));
				}
			};
			this.dice.addSpinnerListener(diceSpinnerListener);

			this.addWest(roll, 100);
			this.addWest(this.dice, 100);
			this.addWest(diceOf, 100);
			this.addWest(this.sides, 100);
			this.addWest(side, 100);
		}

		public int getDice() {
			return (int) this.dice.getValue();
		}

		public int getSides() {
			return (int) this.sides.getValue();
		}
	}

	protected final Constant constant;
	protected final Message message;

	protected final CommandTabImpl actionPanel;
	protected final CommandTabImpl offPanel;
	protected final CommandTabImpl dicePanel;

	protected final ListBox messageActionListBox = new ListBox();

	protected final Button moreDice = new Button();
	protected final List<DiceLine> dices = new ArrayList<CommandViewImpl.DiceLine>();
	private final FlowPanel diceContainer = new FlowPanel();

	@Inject
	public CommandViewImpl(Constant constant, Message message) {
		super(26, Unit.PX);

		this.constant = constant;
		this.message = message;

		this.moreDice.setText("more");

		this.actionPanel = new CommandTabImpl(Unit.PX, message.getButtonGeneric());
		for (MessageAction messageAction : MessageAction.values()) {
			this.messageActionListBox.addItem(messageAction.toLocaleString(), messageAction.name());
		}
		this.actionPanel.add(this.messageActionListBox);
		this.actionPanel.setWidgetRightWidth(this.messageActionListBox, 100, Unit.PX, 100, Unit.PX);
		this.actionPanel.setWidgetBottomHeight(this.messageActionListBox, 0, Unit.PX, 30, Unit.PX);
		this.offPanel = new CommandTabImpl(Unit.PX, message.getButtonGeneric());
		this.dicePanel = new CommandTabImpl(Unit.PX, message.getButtonDice());
		this.add(this.actionPanel, message.getTabAction());
		this.add(this.offPanel, message.getTabOff());
		this.add(this.dicePanel, message.getTabDice());
		this.dicePanel.add(this.moreDice);
		this.dicePanel.setWidgetLeftWidth(this.moreDice, 550, Unit.PX, 100, Unit.PX);
		this.dicePanel.setWidgetBottomHeight(this.moreDice, 0, Unit.PX, 30, Unit.PX);
		final ScrollPanel scrollPanel = new ScrollPanel(this.diceContainer);
		this.dicePanel.add(scrollPanel);
		this.dicePanel.setWidgetLeftWidth(scrollPanel, 0, Unit.PX, 530, Unit.PX);
		this.dicePanel.setWidgetBottomHeight(scrollPanel, 0, Unit.PX, 50, Unit.PX);
		newDiceLine();
	}

	@Override
	public CommandTab getActionTab() {
		return this.actionPanel;
	}

	@Override
	public MessageAction getMessageActionType() {
		return MessageAction.values()[this.messageActionListBox.getSelectedIndex()];
	}

	@Override
	public CommandTab getOffTab() {
		return this.offPanel;
	}

	@Override
	public CommandTab getDiceTab() {
		return this.dicePanel;
	}

	@Override
	public HasClickHandlers getMoreDiceButton() {
		return this.moreDice;
	}

	@Override
	public void newDiceLine() {
		final DiceLine dice = new DiceLine();
		dice.setHeight("20px");
		this.dices.add(dice);
		this.diceContainer.add(dice);
	}

	@Override
	public Map<Integer, Integer> getDices() {
		final Map<Integer, Integer> values = new HashMap<Integer, Integer>();
		for (DiceLine diceLine : this.dices) {
			final int sides = diceLine.getSides();
			final Integer dice = values.get(sides);
			if (dice == null) {
				values.put(sides, diceLine.getDice());
			} else {
				values.put(sides, dice + diceLine.getDice());
			}
		}
		return values;
	}

	@Override
	public void emptyDice() {
		final Iterator<DiceLine> dicesIterator = this.dices.iterator();
		while (dicesIterator.hasNext()) {
			final DiceLine diceLine = dicesIterator.next();
			this.diceContainer.remove(diceLine);
			dicesIterator.remove();
		}
		newDiceLine();
	}

}
